package com.zoe.onelink.doc.operation;

import com.zoe.onelink.doc.property.OnelinkDocProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.web.bind.annotation.RequestMethod;
import springfox.documentation.OperationNameGenerator;
import springfox.documentation.builders.OperationBuilder;
import springfox.documentation.service.Operation;
import springfox.documentation.spi.service.contexts.OperationContext;
import springfox.documentation.spi.service.contexts.RequestMappingContext;
import springfox.documentation.spring.web.plugins.DocumentationPluginsManager;
import springfox.documentation.spring.web.readers.operation.ApiOperationReader;
import springfox.documentation.spring.web.readers.operation.OperationReader;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * <p>标题: </p>
 * <p>描述: </p>
 * <p>版权: Copyright (c) 2022</p>
 * <p>公司: 智业软件股份有限公司</p>
 *
 * @version: 1.0
 * @author: ruansheng
 * @date: 2022-12-30
 */
@Slf4j
public class AdvancedApiOperationReader implements OperationReader, BeanPostProcessor {

    private final DocumentationPluginsManager pluginsManager;
    private final OperationNameGenerator nameGenerator;

    private final Set<RequestMethod> defaultMethods;

    public AdvancedApiOperationReader(DocumentationPluginsManager pluginsManager,
                                      OperationNameGenerator nameGenerator,
                                      OnelinkDocProperties onelinkDocProperties) {
        this.pluginsManager = pluginsManager;
        this.nameGenerator = nameGenerator;

        if (onelinkDocProperties.getDefaultMethods() == null || onelinkDocProperties.getDefaultMethods().isEmpty()) {
            this.defaultMethods = Set.of(RequestMethod.values());
        } else {
            log.info("[OneLinkFrm] [在线文档模块] @RequestMapping接口将默认只生成 {} 接口文档", onelinkDocProperties.getDefaultMethods());
            this.defaultMethods = onelinkDocProperties.getDefaultMethods();
        }
    }

    @Override
    public List<Operation> read(RequestMappingContext outerContext) {

        List<Operation> operations = new ArrayList<>();

        Set<RequestMethod> requestMethods = outerContext.getMethodsCondition();
        Set<RequestMethod> supportedMethods = supportedMethods(requestMethods);

        //Setup response message list
        int currentCount = 0;
        for (RequestMethod httpRequestMethod : supportedMethods) {
            OperationContext operationContext = new OperationContext(new OperationBuilder(nameGenerator),
                    httpRequestMethod,
                    outerContext,
                    currentCount);

            Operation operation = pluginsManager.operation(operationContext);
            if (!operation.isHidden()) {
                operations.add(operation);
                currentCount++;
            }
        }
        operations.sort(outerContext.operationOrdering());

        return operations;
    }

    protected Set<RequestMethod> supportedMethods(Set<RequestMethod> requestMethods) {
        return requestMethods == null || requestMethods.isEmpty()
                ? this.defaultMethods
                : requestMethods;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof ApiOperationReader) {
            bean = this;
        }
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}
